home *** CD-ROM | disk | FTP | other *** search
- /*======================================================================
- L B U F F E R . C
- doc: Mon Apr 26 16:11:25 1993
- dlm: Mon May 17 10:01:05 1993
- (c) 1993 ant@notylia
- uE-Info: 66 6 T 0 0 72 2 2 8 ofnI
- ======================================================================*/
-
- #include <stdio.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/time.h>
-
- /*#define DEBUG /* show ops */
- /*#define MLIMIT 100 /* memory limit */
-
- #define LBSIZE (1024-sizeof(struct lBlock *)-sizeof(int)) /* block size */
- #define LBALLOC() (lBlock *)malloc(sizeof(lBlock)) /* alloc block */
- #define FOREVER while(1)
-
- #define IN 0
- #define OUT 1
-
- typedef struct lBlock { /* live block */
- struct lBlock *next;
- int used;
- char buf[LBSIZE];
- } lBlock;
-
- static lBlock *head;
-
- static void fill(in,statusP) /* fill buffer */
- int in,statusP;
- {
- lBlock *tail;
- int nRead,remain,nBlocks=0,maxFd;
- fd_set selRead;
-
- head = tail = LBALLOC(); /* alloc 1st */
- if (head == NULL) {
- fprintf(stderr,"lBuffer malloc() failed\n");
- exit(1);
- } else nBlocks++;
- head->used = 0;
- head->next = NULL;
- remain = LBSIZE;
-
- #ifdef DEBUG
- fprintf(stderr,"Filling lBuffer...\n");
- #endif
- do { /* build buffer */
- FD_ZERO(&selRead); /* detect death */
- FD_SET(in,&selRead); maxFd = in;
- if (statusP >= 0)
- FD_SET(statusP,&selRead);
- if (statusP > maxFd)
- maxFd = statusP;
- if (select(maxFd+1,&selRead,NULL,NULL,NULL) < 0) {
- perror("lBuffer select");
- exit(1);
- }
- if ((statusP >= 0) && /* father dead */
- FD_ISSET(statusP,&selRead)) {
- #ifdef DEBUG
- fprintf(stderr,"Exiting due to parent death...\n");
- #endif
- exit(1);
- }
-
- nRead = read(in,&tail->buf[tail->used], /* read block */
- remain);
- if (nRead < 0) {
- perror("lBuffer read");
- exit(1);
- }
- tail->used += nRead;
- remain -= nRead;
-
- if (nRead == 0) break; /* eof */
- if (tail->buf[tail->used-1] == '\0') {
- tail->used--;
- break;
- }
-
- if (remain == 0) { /* next block */
- tail->next = LBALLOC();
- if (tail->next == NULL) {
- fprintf(stderr,"lBuffer malloc() failed\n");
- exit(1);
- } else {
- nBlocks++;
- #ifdef MLIMIT
- if (nBlocks > MLIMIT) {
- fprintf(stderr,"lBuffer MLIMIT\n");
- exit(1);
- }
- #endif
- }
- tail = tail->next;
- tail->used = 0;
- tail->next = NULL;
- remain = LBSIZE;
- }
- } FOREVER;
- close(in);
- }
-
- static void drain(out) /* drain buffer */
- int out;
- {
- lBlock *cur;
-
- cur = head;
- #ifdef DEBUG
- fprintf(stderr,"Draining lBuffer...\n");
- #endif
- do {
- if (write(out,cur->buf,cur->used) != cur->used) {
- perror("lBuffer write");
- exit(1);
- }
- cur = cur->next;
- } while (cur != NULL);
- close(out);
- }
-
- /*======================================================================*/
-
- static killed() /* killed nicely */
- {
- exit(0);
- }
-
- lPreBuffer(out1,out2) /* buf twice */
- int out1[2],out2[2];
- {
- int pid,statusP[2];
-
- if (pipe(statusP) < 0) { /* status pipe */
- perror("lBuffer pipe");
- exit(1);
- }
- if ((pid = fork()) < 0) { /* build proc */
- perror("lBuffer fork");
- exit(1);
- }
- if (pid > 0) { /* father continues */
- close(statusP[IN]);
- close(out1[OUT]);
- close(out2[OUT]);
- return pid;
- }
-
- signal(SIGALRM,SIG_IGN); /* child buffers */
- signal(SIGINT,SIG_IGN); /* enable killing */
- signal(SIGUSR1,killed);
- close(statusP[OUT]);
- close(out1[IN]);
- close(out2[IN]);
- fill(IN,statusP[IN]);
- signal(SIGUSR1,SIG_IGN); /* disable killing */
- drain(out1[OUT]);
- drain(out2[OUT]);
- exit(0);
- }
-
- lPostBuffer(in,out) /* buf once */
- int in,out[2];
- {
- int pid;
-
- #ifdef DEBUG
- fprintf(stderr,"lPostBuffer()\n");
- #endif
- if ((pid = fork()) < 0) { /* build proc */
- perror("lBuffer fork");
- exit(1);
- }
- if (pid > 0) { /* father continues */
- close(out[OUT]);
- return pid;
- }
-
- signal(SIGALRM,SIG_IGN); /* child buffers */
- close(out[IN]);
- fill(in,-1);
- drain(out[OUT]);
- #ifdef DEBUG
- fprintf(stderr,"lPostBuffer normal exit\n");
- #endif
- exit(0);
- }
-